package com.managertrade.service.impl;

import com.managertrade.dto.vo.MenuVO;
import com.managertrade.dao.mysql.entity.SysMenu;
import com.managertrade.dao.mysql.entity.SysRoleMenu;
import com.managertrade.dao.mysql.entity.SysUserRole;
import com.managertrade.dao.mysql.repository.SysMenuRepository;
import com.managertrade.dao.mysql.repository.SysRoleMenuRepository;
import com.managertrade.dao.mysql.repository.SysUserRoleRepository;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class MenuServiceImpl implements MenuService{

    @Resource
    private SysUserRoleRepository userRoleRepo;
    @Resource
    private SysRoleMenuRepository roleMenuRepo;
    @Resource
    private SysMenuRepository menuRepo;

    // 主方法：根据用户 ID 获取菜单树
    public List<MenuVO> getMenuTreeByUserId(Long userId) {
        List<SysMenu> menus = getMenuByUserId(userId);
        // 构建菜单树
        List<MenuVO> tree = buildMenuTree(menus, 0L); // 顶级菜单 parentId = 0
        return tree;
    }

    @Override
    public List<MenuVO> getMenuTreeAll() {
        List<SysMenu> allMenu = menuRepo.findAll();
        // 构建菜单树
        List<MenuVO> tree = buildMenuTree(allMenu, 0L); // 顶级菜单 parentId = 0
        return tree;
    }

    @Override
    public List<MenuVO> getMenuRoleId(Long roleId) {
        List<SysRoleMenu> roleMenus = roleMenuRepo.findByRoleId(roleId);
        List<Long> menuIds = roleMenus.stream().map(SysRoleMenu::getMenuId).distinct().collect(Collectors.toList());
        List<SysMenu> menus = menuRepo.findByIdIn(menuIds);
        return menus.stream().map(k-> toVO(k)).collect(Collectors.toList());
    }

    public List<SysMenu> getMenuByUserId(Long userId) {
        List<SysUserRole> userRoles = userRoleRepo.findByUserId(userId);
        List<Long> roleIds = userRoles.stream().map(SysUserRole::getRoleId).collect(Collectors.toList());

        if (roleIds.isEmpty()){
            return Collections.EMPTY_LIST;
        }
        List<SysRoleMenu> roleMenus = roleMenuRepo.findByRoleIdIn(roleIds);
        List<Long> menuIds = roleMenus.stream().map(SysRoleMenu::getMenuId).distinct().collect(Collectors.toList());
        List<SysMenu> menus = menuRepo.findByIdIn(menuIds);
        return menus;
    }

    @Override
    public List<String> getButtonPermsByUserId(Long userId) {
        List<SysUserRole> userRoles = userRoleRepo.findByUserId(userId);
        List<Long> roleIds = userRoles.stream().map(SysUserRole::getRoleId).collect(Collectors.toList());

        if (roleIds.isEmpty()) return Collections.EMPTY_LIST;

        List<SysRoleMenu> roleMenus = roleMenuRepo.findByRoleIdIn(roleIds);
        List<Long> menuIds = roleMenus.stream().map(SysRoleMenu::getMenuId).distinct().collect(Collectors.toList());

        List<SysMenu> menus = menuRepo.findByIdIn(menuIds);

        return menus.stream()
                .filter(m -> m.getType() == 2) // 仅按钮类型
                .map(SysMenu::getPerms)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    // 递归构建菜单树
    private List<MenuVO> buildMenuTree(List<SysMenu> menus, Long parentId) {
        List<MenuVO> result = new ArrayList<>();

        for (SysMenu menu : menus) {
            if (Objects.equals(menu.getParentId(), parentId)) {
                MenuVO vo = toVO(menu);

                List<MenuVO> children = buildMenuTree(menus, menu.getId());
                vo.setChildren(children);

                result.add(vo);
            }
        }

        // 排序
        result.sort(Comparator.comparingInt(m -> Optional.ofNullable(m.getSort()).orElse(0)));

        return result;
    }

    // 实体转 VO
    private MenuVO toVO(SysMenu menu) {
        MenuVO vo = new MenuVO();
        vo.setId(menu.getId());
        vo.setName(menu.getName());
        vo.setPath(menu.getPath());
        vo.setComponent(menu.getComponent());
        vo.setPerms(menu.getPerms());
        vo.setType(menu.getType());
        vo.setParentId(menu.getParentId());
        vo.setSort(menu.getSort());
        return vo;
    }
}
